package cn.sskxyz.security.authorization.service;

import cn.sskxyz.mybatis.mode.Page;
import cn.sskxyz.security.authorization.dao.Oauth2ClientDao;
import cn.sskxyz.security.authorization.model.Oauth2Client;
import cn.sskxyz.security.authorization.model.SecurityService;
import cn.sskxyz.security.authorization.web.args.ClientInfoArgs;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.stereotype.Service;

import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class Oauth2ClientService implements ClientDetailsService, InitializingBean {
    @Autowired
    private Oauth2ClientDao oauth2ClientDao;

    private Set<String> defaultGrantTypes;

    @Override
    public void afterPropertiesSet() throws Exception {
        this.defaultGrantTypes = Arrays.stream("authorization_code,refresh_token,password,client_credentials".split(","))
                .collect(Collectors.toSet());
    }

    @Override
    @Cacheable(value = "client",key = "#clientId")
    public Oauth2Client loadClientByClientId(String clientId) throws ClientRegistrationException {
        Oauth2Client clientDetails = oauth2ClientDao.loadClientByClientId(clientId);

        if (clientDetails != null) {
            String scopes = oauth2ClientDao.selectClientScopeFromService(clientId);
            if (scopes != null && !scopes.isEmpty()) {
                clientDetails.setScope(scopes);
            }
            String authority = oauth2ClientDao.selectClientAuthorityFromService(clientId);
            if (authority != null && !authority.isEmpty()) {
                clientDetails.setAuthorities(authority);
            }
        }
        return clientDetails;
    }

    public Page<List<Oauth2Client>> queryClientList(int currentPage, int pageSize) {
        Page<List<Oauth2Client>> page = new Page<>(currentPage, pageSize);
        List<Oauth2Client> clientList = oauth2ClientDao.selectClientList(page);
        page.setData(clientList);
        return page;
    }

    public Oauth2Client addOauth2Client(ClientInfoArgs clientInfo) {
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.setSeed(System.currentTimeMillis());
        String clientId = Base64.getUrlEncoder().encodeToString(secureRandom.generateSeed(12));
        String clientSecret = Base64.getUrlEncoder().encodeToString(secureRandom.generateSeed(24));
        clientInfo.setClientId(clientId);
        clientInfo.setClientSecret(clientSecret);
        if (clientInfo.getScope() == null || clientInfo.getScope().trim().isEmpty()) {
            clientInfo.setScope(Collections.singleton("app"));
        }
        if (clientInfo.getGrantTypes() == null || clientInfo.getGrantTypes().trim().isEmpty()) {
            clientInfo.setGrantTypes(defaultGrantTypes);
        }
        oauth2ClientDao.insertSingleClient(clientInfo);
        return loadClientByClientId(clientId);
    }

    @CacheEvict(value = "client", key = "#clientInfo.clientId")
    public void changeClientInfo(ClientInfoArgs clientInfo) {
        oauth2ClientDao.updateClient(clientInfo);
    }

    public List<SecurityService> queryServiceListByClientId(String clientId) {
        List<SecurityService> services = oauth2ClientDao.selectAccessableService(clientId);
        return services;
    }
}
